package com.zc.im.netty.handler;

import com.alibaba.fastjson.JSONObject;
import com.zc.im.model.user.HeartbeatModel;
import com.zc.im.model.user.ZcAdminUser;
import com.zc.im.model.user.ZcUser;
import com.zc.im.netty.global.NettyGlobalData;
import com.zc.im.rabbitmq.Runner;
import com.zc.im.service.user.UserService;
import com.zc.im.service.user.ZcAdminUseService;
import com.zc.im.util.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;

public  class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

	private Logger log = LoggerFactory.getLogger(TextWebSocketFrameHandler.class);


	private final ChannelGroup group;



	public TextWebSocketFrameHandler(ChannelGroup group) {
		super();
		this.group = group;
	}
	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt)
			throws Exception {
		if(evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE){
			ctx.pipeline().remove(HttpRequestHandler.class);
			group.add(ctx.channel());
			ctx.channel().writeAndFlush(new TextWebSocketFrame("1000"));
		}else{
			super.userEventTriggered(ctx, evt);
		}
	}



	@Override
	protected void channelRead0(ChannelHandlerContext channelHandlerContext,
								TextWebSocketFrame textWebSocketFrame) throws Exception {
		//write方法从TailHandler开始, 穿过中间自定义的各种handler以后到达HeadHandler, 然后调用了HeadHandler的成员变量Unsafe的write
		//也就是说调用write方法实际上并不是真的将消息写出去, 而是将消息和此次操作的promise放入到了一个队列中
		//flush也是从Tail开始, 最后到Head, 最终调用的也是Head里的unsafe的flush0()方法, 然后flush0()里再调用doWrite()方法, 如下:
		try{
			if (textWebSocketFrame == null || StringUtils.isEmpty(textWebSocketFrame.text())) {
				log.error("TextWebSocketFrame 为空");
				return;
			}
			JSONObject jsonObject = JsonUtils.strToJsonObj(textWebSocketFrame.text());
			if(!jsonObject.containsKey(ImGolbalTypeContext.IM_TYPE)){
				log.error("缺少必要参数 jsonObject：", jsonObject.toJSONString());
				return;
			}
			String currentMsgType = jsonObject.get(ImGolbalTypeContext.IM_TYPE).toString();
			String userId = null;
			if(jsonObject.containsKey(ImGolbalTypeContext.IM_USER_ID)){
				userId = jsonObject.get(ImGolbalTypeContext.IM_USER_ID).toString();
			}
			// 客服登陆进入
			if(ImGolbalTypeContext.IM_CUSTOMER_SERVICE_LOGIN.equals(currentMsgType)){
				ZcAdminUseService adminUserService = (ZcAdminUseService) SpringContextUtils.getBeanByClass(ZcAdminUseService.class);
				ZcAdminUser  zcAdminUserModel = adminUserService.findZcAdminUser(Integer.parseInt(userId));
				if(zcAdminUserModel == null){
					log.error("当前客服登陆用户不存在");
					return ;
				}
				setImCumtormerGlobalTypeContent(userId, channelHandlerContext);
				return;
			}
			//心跳检测
			if (ImGolbalTypeContext.IM_HEARTBEAT.equals(currentMsgType)) {
				HeartbeatModel heartbeatModel = new HeartbeatModel();
				heartbeatModel.setType("heartbeat");
				heartbeatModel.setResult("1000");
				String heartbeat = JsonUtils.objToStr(heartbeatModel);
				channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(heartbeat));
			}
			//用户加入
			if(ImGolbalTypeContext.IM_JOIN.equals(currentMsgType)){
				setImGlobalTypeContent(userId, channelHandlerContext);
				return;
			}
			//发送消息到消息队列
			Runner runner = (Runner) SpringContextUtils.getBeanByClass(Runner.class);
			log.error("收到Netty 消息" + textWebSocketFrame.text());
			runner.run(textWebSocketFrame.text());

		}catch (Exception e){
			log.error(e.getMessage(), e);
		}
	}


	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		ctx.close();
		cause.printStackTrace();
	}


	//	{"type":"join","userId":"1278030"}
	//	socket.send('{"type":"msg","userId":"1278029","info":"今天天气不错","targetId":"1278030"}');
	//	socket.send('{"type":"customer_service","userId":"1278029"}');
	/*public String handlerMsgTypeAndSendMsg(TextWebSocketFrame msg, ChannelHandlerContext channelHandlerContext,
										   String currentMsgType, String userId, String targetUserId,
										   String content, String groupId) {
		String msgType = null;
		switch (currentMsgType) {
			// 用户登陆进入
			case ImGolbalTypeContext.IM_JOIN:
				UserService userService = (UserService) SpringContextUtils.getBeanByClass(UserService.class);
				ZcUser zcUserModel = userService.queryUser(Integer.parseInt(userId));
				if(zcUserModel == null){
					log.error("当前用户不存在");
					return msgType;
				}
						setImGlobalTypeContent(userId, channelHandlerContext);
				break;
			// 客服登陆进入
			case ImGolbalTypeContext.IM_CUSTOMER_SERVICE_LOGIN:

				ZcAdminUseService adminUserService = (ZcAdminUseService) SpringContextUtils.getBeanByClass(ZcAdminUseService.class);
				ZcAdminUser  zcAdminUserModel = adminUserService.findZcAdminUser(Integer.parseInt(userId));
				if(zcAdminUserModel == null){
					log.error("当前客服登陆用户不存在");
					return msgType;
				}
				setImCumtormerGlobalTypeContent(userId, channelHandlerContext);
				break;
			// 与客服绑定
			// 点击与客服聊天 有客服 直接聊天 无客服 分配客服聊天
			case ImGolbalTypeContext.IM_CUSTOMER_SERVICE:
				if(StringUtils.isEmpty(userId)){
					log.error("分配客服失败,用户ID 为空！");
					return msgType;
				}
				setCustomerService(userId, channelHandlerContext, ImGolbalTypeContext.IM_CUSTOMER_SERVICE);
				break;
			// 个人与企业
			case ImGolbalTypeContext.IM_MSG_TYPE_TO_PEOPLE:
				List<String> member = new ArrayList<>();
				member.add(targetUserId);
				sendMsgToTargetUsers(userId, member, content, channelHandlerContext, ImGolbalTypeContext.IM_MSG_TYPE_TO_PEOPLE);
				break;
			//个人到群组
			case ImGolbalTypeContext.IM_MSG_TYPE_TO_GROUP:
				if(StringUtils.isEmpty(groupId)){
					log.error("群组ID为空");
					break;
				}
				// 当前登录用户对象
				// 通过群组ID 查询群组中所有的群成员
				ImGroupMemberService memberService = (ImGroupMemberService) SpringContextUtils.getBeanByClass(ImGroupMemberService.class);
				ZcImGroupMember zcImGroupMemberModel = new ZcImGroupMember();
				zcImGroupMemberModel.setGroupId(Integer.parseInt(groupId));

				List<ZcImGroupMember> groupMemberModels =  memberService.queryAllGroupMember(zcImGroupMemberModel);
				if(groupMemberModels== null|| groupMemberModels.size() == 0){
					break;
				}
				List<String> groupMembers = new ArrayList<>();
				for(ZcImGroupMember memberModel: groupMemberModels){
					groupMembers.add(memberModel.getUserId().toString());
				}
				sendMsgToTargetUsers(userId, groupMembers, content, channelHandlerContext, ImGolbalTypeContext.IM_MSG_TYPE_TO_GROUP);
				break;
			case ImGolbalTypeContext.IM_MSG_TYPE_TO_READ_STATUS:
				List<String> readMembers = new ArrayList<>();
				readMembers.add(targetUserId);
				sendMsgToTargetUsers(userId, readMembers, ImGolbalTypeContext.IM_MSG_READ_STATUS_READ, channelHandlerContext, ImGolbalTypeContext.IM_MSG_TYPE_TO_READ_STATUS);
				//消息至未已读
				ImUnreadNumService unreadNumService = (ImUnreadNumService) SpringContextUtils.getBeanByClass(ImUnreadNumService.class);
				unreadNumService.updateUnreadNumToDef(Integer.parseInt(targetUserId), Integer.parseInt(userId),
						ImGolbalTypeContext.IM_MSG_TYPE_TO_PEOPLE);

				break;
			default:
				msgType = String.valueOf(ImGolbalTypeContext.IM_MSG_TYPE_ERROR);//返回错误吗1003json错误。为发现type
				channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(content));
		}
		return msgType;
	}*/

	//登录用户后 把用户添加到在线全局用户中
	public void setImGlobalTypeContent(String userId, ChannelHandlerContext channelHandlerContext){
		try{
			if(StringUtils.isEmpty(userId)){
				return;
			}
			UserService userService = (UserService) SpringContextUtils.getBeanByClass(UserService.class);
			ZcUser userModel = userService.queryUser(Integer.parseInt(userId));
			if(userModel == null){
				return;
			}
			//企业 个人	客服为个人小畅10	客服为企业小畅9
			//NettyGlobalData.onlineUser.put(channelHandlerContext.channel().id().toString(), userModel);
			group.add(channelHandlerContext.channel());
			NettyGlobalData.userIdAndChannelMapping.put(userId, channelHandlerContext.channel());
		}catch (Exception e){
			log.error(e.getMessage(), e);
		}

	}


	//登录客服成功后 把客服添加到在线全局用户中
	public void setImCumtormerGlobalTypeContent(String userId, ChannelHandlerContext channelHandlerContext){
		try{
			if(StringUtils.isEmpty(userId)){
				return;
			}
			ZcAdminUseService adminUserService = (ZcAdminUseService) SpringContextUtils.getBeanByClass(ZcAdminUseService.class);
			ZcAdminUser  zcAdminUserModel = adminUserService.findZcAdminUser(Integer.parseInt(userId));
			if(zcAdminUserModel == null){
				return;
			}
			//企业 个人	客服为个人小畅10	客服为企业小畅9
			//NettyGlobalData.onlineUser.put(channelHandlerContext.channel().id().toString(), userModel);
			group.add(channelHandlerContext.channel());
			NettyGlobalData.userIdAndChannelMapping.put(userId, channelHandlerContext.channel());
		}catch (Exception e){
			log.error(e.getMessage(), e);
		}

	}

	//设置客服
	/*public void setCustomerService(String userId, ChannelHandlerContext channelHandlerContext, String type){
		if(StringUtils.isEmpty(userId)){
			log.error("分配客服失败,用户ID 为空！");
			return;
		}
		CustomerService customerService = (CustomerService) SpringContextUtils.getBeanByClass(CustomerService.class);
		//查询 客服信息
		Map<String, Object> customerServiceMap = customerService.queryOrSaveUserRelationCustomerService(Integer.parseInt(userId));
		if(customerServiceMap == null || customerServiceMap.size() == 0){
			log.error("数据异常");
			return;
		}
		ZcAdminUser customerServiceUserInfo = (ZcAdminUser) customerServiceMap.get(ImGolbalTypeContext.IM_CUSTOMER_SERVICE_INFO);
		if(customerServiceUserInfo == null){
			log.error("数据异常");
			return;
		}
		ZcCustomerServiceModel zcCustomerServiceModel = new ZcCustomerServiceModel();
		zcCustomerServiceModel.setNickName(customerServiceUserInfo.getUserName());
		zcCustomerServiceModel.setUserId(customerServiceUserInfo.getUid());
		zcCustomerServiceModel.setPortrait(customerServiceUserInfo.getPicHead());
		//返回客服信息
		String msgStr = setNettyMsg(userId, customerServiceUserInfo.getUid().toString(),zcCustomerServiceModel , ImGolbalTypeContext.IM_MSG_TYPE_TO_CUSTOMER_SERVICE);
		channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(msgStr));
	}*/

	/**
	 * 发送消息到目标集合
	 * 2017-7-8 20:38:30
	 * @param targets
	 * @param content
	 * @param channelHandlerContext
	 * @return
	 */
	/*private JSONObject sendMsgToTargetUsers(String userId, List<String> targets, String content, ChannelHandlerContext channelHandlerContext, String type) {
		JSONObject json = new JSONObject();
		if(targets == null || targets.size() == 0){
			return json;
		}*/
		/*//在线用户列表
		ZcUser onlineUser = NettyGlobalData.onlineUser.get(channelHandlerContext.channel().id().toString());
		//在线客服列表
		ZcUser onlineCustomerUser = NettyGlobalData.onlineCustomer.get(channelHandlerContext.channel().id().toString());*/
		//判断数据库中是否存在当前用户
		/*for(String targetUserId: targets){
			execSendMsg(userId, targetUserId, type, content);
		}
		return json;
	}*/





	/**
	 * 处理消息持久化
	 * 2017-7-8 21:15:43
	 * @param textWebSocketFrame
	 */
	/*public void handlerPersistenceMsg(TextWebSocketFrame textWebSocketFrame, String currentMsgType, String userId, String targetUserId,
									  String content, String groupId) {
		ZcImMsgHistoryModel historyModel = new ZcImMsgHistoryModel();
		historyModel.setContent(content);
		historyModel.setMsgAgreementType(currentMsgType);
		if(ImGolbalTypeContext.IM_MSG_TYPE_TO_PEOPLE.equals(currentMsgType)){
			historyModel.setMsgType(ImGolbalTypeContext.IM_MSG_TYPE_PEOPLE);
			historyModel.setTargetObjType(ImGolbalTypeContext.IM_MSG_TYPE_PEOPLE);
			historyModel.setTargetObjId(Integer.parseInt(targetUserId));
		}else{
			historyModel.setMsgType(ImGolbalTypeContext.IM_MSG_TYPE_GROUP);
			historyModel.setTargetObjType(ImGolbalTypeContext.IM_MSG_TYPE_GROUP);
			historyModel.setTargetObjId(Integer.parseInt(groupId));
		}
		historyModel.setSourceObjId(Integer.parseInt(userId));

		historyModel.setSourceObjType(ImGolbalTypeContext.IM_MSG_TYPE_PEOPLE);

		historyModel.setCreatedTime(new Date());
		historyModel.setUpdatedTime(new Date());
		historyModel.setMsgReadStatus(ImGolbalTypeContext.IM_MSG_READ_STATUS_UNREAD);
		historyModel.setStatus(ImGolbalTypeContext.STATUS_VALID);

		ImMsgHistoryService imMsgHistoryService = (ImMsgHistoryService) SpringContextUtils.getBeanByClass(ImMsgHistoryService.class);
		imMsgHistoryService.insertImMsgHistory(historyModel);
	}*/


	/*public String setNettyMsg(String userId, String targetId, Object jsonObject, String type){

		UserService userService = (UserService) SpringContextUtils.getBeanByClass(UserService.class);
		ZcUser sendUser = userService.findUser(Integer.parseInt(userId));

		NettyMsgModel msgModel = new NettyMsgModel();
		msgModel.setSendTime(DateUtils.dateFormatStrYmdHms(new Date()));
		msgModel.setTargetId(targetId);
		msgModel.setUserId(userId);
		msgModel.setInfo(jsonObject);
		msgModel.setType(type);
		if(sendUser!= null){
			msgModel.setPicHead(sendUser.getPicHead());
			msgModel.setName(sendUser.getNickname());
		}
		return JsonUtils.objToStr(msgModel);
	}*/


	/**
	 * 设置未读消息
	 * 2017-7-15 19:17:46
	 * @param userId
	 * @return
	 */
	/*public void setMsgUnread(Integer userId, Integer targetId, String type){
		ImUnreadNumService unreadNumService = (ImUnreadNumService) SpringContextUtils.getBeanByClass(ImUnreadNumService.class);
		unreadNumService.saveOrUpdateUnreadNum(userId, targetId, type);
	}*/


	/*public void execSendMsg(String userId, String targetUserId, String type, String content){

		if(ImGolbalTypeContext.IM_MSG_TYPE_TO_PEOPLE.equals(type)){
			setMsgUnread(Integer.parseInt(userId), Integer.parseInt(targetUserId), type);
		}
		Channel channel = NettyGlobalData.userIdAndChannelMapping.get(targetUserId);
		if(channel == null){
			return;
		}
		String msg = setNettyMsg(userId, targetUserId, content, type);
		channel.writeAndFlush(new TextWebSocketFrame(msg));
	}*/
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.err.println("---" + ctx.channel().remoteAddress() + " is active---");
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		System.err.println("---" + ctx.channel().remoteAddress() + " is inactive---");
	}

	protected void handleReaderIdle(ChannelHandlerContext ctx) {
		System.err.println("---READER_IDLE---");
	}

	protected void handleWriterIdle(ChannelHandlerContext ctx) {
		System.err.println("---WRITER_IDLE---");
	}

	protected void handleAllIdle(ChannelHandlerContext ctx) {
		System.err.println("---ALL_IDLE---");
	}
}
